Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Displaying Raw • Download


LXMF/LXMF.py ca55c1fd7a911a8fbb2edf9cebfee6fd4cbe0d34 (ca55c1fd) Text, 25.46 KB

Tff7b72import T7ee787math
Tff7b72import T7ee787time
Tff7b72import T7ee787threading
Tff7b72import T7ee787RNS
Tff7b72import T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787umsgpack Tff7b72as T7ee787msgpack

Te6edf3APP_NAME Tff7b72= Ta5d6ff"Ta5d6fflxmfTa5d6ff"

Tff7b72class T56d364LXMessageTb4b4b4:
Te6edf3DRAFT Tff7b72= T79c0ff0x00
Te6edf3OUTBOUND Tff7b72= T79c0ff0x01
Te6edf3SENDING Tff7b72= T79c0ff0x02
Te6edf3SENT Tff7b72= T79c0ff0x04
Te6edf3DELIVERED Tff7b72= T79c0ff0x08
Te6edf3FAILED Tff7b72= T79c0ff0xFF
Te6edf3states Tff7b72= Tb4b4b4[Te6edf3DRAFTTb4b4b4, Te6edf3OUTBOUNDTb4b4b4, Te6edf3SENDINGTb4b4b4, Te6edf3SENTTb4b4b4, Te6edf3DELIVEREDTb4b4b4, Te6edf3FAILEDTb4b4b4]

Te6edf3UNKNOWN Tff7b72= T79c0ff0x00
Te6edf3PACKET Tff7b72= T79c0ff0x01
Te6edf3RESOURCE Tff7b72= T79c0ff0x02
Te6edf3representations Tff7b72= Tb4b4b4[Te6edf3UNKNOWNTb4b4b4, Te6edf3PACKETTb4b4b4, Te6edf3RESOURCETb4b4b4]

Te6edf3OPPORTUNISTIC Tff7b72= T79c0ff0x01
Te6edf3DIRECT Tff7b72= T79c0ff0x02
Te6edf3PROPAGATED Tff7b72= T79c0ff0x03
Te6edf3valid_methods Tff7b72= Tb4b4b4[Te6edf3OPPORTUNISTICTb4b4b4, Te6edf3DIRECTTb4b4b4, Te6edf3PROPAGATEDTb4b4b4]

Te6edf3SOURCE_UNKNOWN Tff7b72= T79c0ff0x01
Te6edf3SIGNATURE_INVALID Tff7b72= T79c0ff0x02
Te6edf3unverified_reasons Tff7b72= Tb4b4b4[Te6edf3SOURCE_UNKNOWNTb4b4b4, Te6edf3SIGNATURE_INVALIDTb4b4b4]

Te6edf3DESTINATION_LENGTH Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8ffTRUNCATED_HASHLENGTHTff7b72/Tff7b72/T79c0ff8
Te6edf3SIGNATURE_LENGTH Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8ffSIGLENGTHTff7b72/Tff7b72/T79c0ff8

T8b949e# LXMF overhead is 163 bytes per message:
T8b949e# 10 bytes for destination hash
T8b949e# 10 bytes for source hash
T8b949e# 128 bytes for RSA signature
T8b949e# 8 bytes for timestamp
T8b949e# 7 bytes for msgpack structure
Te6edf3LXMF_OVERHEAD Tff7b72= T79c0ff2Tff7b72*Te6edf3DESTINATION_LENGTH Tff7b72+ Te6edf3SIGNATURE_LENGTH Tff7b72+ T79c0ff8 Tff7b72+ T79c0ff7

T8b949e# With an MTU of 500, the maximum RSA-encrypted
T8b949e# amount of data we can send in a single packet
T8b949e# is given by the below calculation; 258 bytes.
Te6edf3RSA_PACKET_MDU Tff7b72= Te6edf3RNSTff7b72.Td2a8ffPacketTff7b72.Td2a8ffRSA_MDU
T8b949e# The max content length we can fit in LXMF message
T8b949e# inside a single RNS packet is the RSA MDU, minus
T8b949e# the LXMF overhead. We can optimise a bit though, by
T8b949e# inferring the destination hash from the destination
T8b949e# field of the packet, therefore we also add the length
T8b949e# of a destination hash to the calculation. With default
T8b949e# RNS and LXMF parameters, the largest single-packet
T8b949e# LXMF message we can send is 105 bytes. If a message
T8b949e# is larger than that, a Reticulum link will be used.
Te6edf3RSA_PACKET_MAX_CONTENT Tff7b72= Te6edf3RSA_PACKET_MDU Tff7b72- Te6edf3LXMF_OVERHEAD Tff7b72+ Te6edf3DESTINATION_LENGTH
T8b949e# Links can carry a significantly larger MDU, due to
T8b949e# more efficient elliptic curve cryptography. The link
T8b949e# MDU with default Reticulum parameters is 415 bytes.
Te6edf3LINK_PACKET_MDU Tff7b72= Te6edf3RNSTff7b72.Td2a8ffLinkTff7b72.Td2a8ffMDU

T8b949e# Which means that we can deliver single-packet LXMF
T8b949e# messages with content of up to 252 bytes over a link.
T8b949e# If a message is larger than that, LXMF will sequence
T8b949e# and transfer it as a RNS resource over the link instead.
Te6edf3LINK_PACKET_MAX_CONTENT Tff7b72= Te6edf3LINK_PACKET_MDU Tff7b72- Te6edf3LXMF_OVERHEAD

T8b949e# For plain packets without encryption, we can
T8b949e# fit up to 324 bytes of content.
Te6edf3PLAIN_PACKET_MDU Tff7b72= Te6edf3RNSTff7b72.Td2a8ffPacketTff7b72.Td2a8ffPLAIN_MDU
Te6edf3PLAIN_PACKET_MAX_CONTENT Tff7b72= Te6edf3PLAIN_PACKET_MDU Tff7b72- Te6edf3LXMF_OVERHEAD Tff7b72+ Te6edf3DESTINATION_LENGTH

T8b949e# Descriptive strings regarding transport encryption
Te6edf3ENCRYPTION_DESCRIPTION_RSA Tff7b72= Ta5d6ff"Ta5d6ffRSA-Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8ffKEYSIZETb4b4b4)
Te6edf3ENCRYPTION_DESCRIPTION_AES Tff7b72= Ta5d6ff"Ta5d6ffAES-128Ta5d6ff"
Te6edf3ENCRYPTION_DESCRIPTION_EC Tff7b72= Ta5d6ff"Ta5d6ffEC-SECP256R1Ta5d6ff"
Te6edf3ENCRYPTION_DESCRIPTION_UNENCRYPTED Tff7b72= Ta5d6ff"Ta5d6ffUnencryptedTa5d6ff"

Tff7b72def Tff7b72__str__Tb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffhash Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff<LXMessage Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffhexrepTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhashTb4b4b4, Te6edf3delimitTff7b72=Tff7b72FalseTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff>Ta5d6ff"
Tff7b72elseTb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff<LXMessage>Ta5d6ff"

Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3destinationTb4b4b4, Te6edf3sourceTb4b4b4, Te6edf3content Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3title Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3fields Tff7b72= Tff7b72NoneTb4b4b4, Te6edf3desired_method Tff7b72= Tff7b72NoneTb4b4b4, Te6edf3destination_hash Tff7b72= Tff7b72NoneTb4b4b4, Te6edf3source_hash Tff7b72= Tff7b72NoneTb4b4b4)Tb4b4b4:
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3destinationTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4) Tff7b72or Te6edf3destination Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__destination Tff7b72= Te6edf3destination
Tff7b72if Te6edf3destination Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdestination_hash Tff7b72= Te6edf3destinationTff7b72.Td2a8ffhash
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdestination_hash Tff7b72= Te6edf3destination_hash
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffLXMessage initialised with invalid destinationTa5d6ff"Tb4b4b4)

Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3sourceTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4) Tff7b72or Te6edf3source Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__source Tff7b72= Te6edf3source
Tff7b72if Te6edf3source Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffsource_hash Tff7b72= Te6edf3sourceTff7b72.Td2a8ffhash
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffsource_hash Tff7b72= Te6edf3source_hash
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffLXMessage initialised with invalid sourceTa5d6ff"Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffset_title_from_stringTb4b4b4(Te6edf3titleTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffset_content_from_stringTb4b4b4(Te6edf3contentTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffset_fieldsTb4b4b4(Te6edf3fieldsTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffpayload Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8fftimestamp Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffsignature Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffhash Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffpacked Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffprogress Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffstate Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffDRAFT
Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffUNKNOWN

Tff7b72selfTff7b72.Td2a8ffincoming Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8ffsignature_validated Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8ffunverified_reason Tff7b72= Tff7b72None

Tff7b72selfTff7b72.Td2a8ffrepresentation Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffUNKNOWN
Tff7b72selfTff7b72.Td2a8ffdesired_method Tff7b72= Te6edf3desired_method
Tff7b72selfTff7b72.Td2a8ffdelivery_attempts Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffpacket_representation Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffresource_representation Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff__delivery_destination Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff__delivery_callback Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8fffailed_callback Tff7b72= Tff7b72None

Tff7b72def Td2a8ffset_title_from_stringTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3title_stringTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8fftitle Tff7b72= Te6edf3title_stringTff7b72.Td2a8ffencodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffset_title_from_bytesTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3title_bytesTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8fftitle Tff7b72= Te6edf3title_bytes

Tff7b72def Td2a8fftitle_as_stringTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8fftitleTff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffset_content_from_stringTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3content_stringTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffcontent Tff7b72= Te6edf3content_stringTff7b72.Td2a8ffencodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffset_content_from_bytesTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3content_bytesTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffcontent Tff7b72= Te6edf3content_bytes

Tff7b72def Td2a8ffcontent_as_stringTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ffcontentTff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffset_fieldsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3fieldsTb4b4b4)Tb4b4b4:
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3fieldsTb4b4b4, Tffa657dictTb4b4b4) Tff7b72or Te6edf3fields Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8fffields Tff7b72= Te6edf3fields
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffLXMessage property Tffea00\"Ta5d6fffieldsTffea00\"Ta5d6ff can only be dict or NoneTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffget_fieldsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ff__fields

Tff7b72def Td2a8ffset_destinationTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3destinationTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffdestination Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3destinationTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__destination Tff7b72= Te6edf3destination
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffInvalid destination set on LXMessageTa5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffCannot reassign destination on LXMessageTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffget_destinationTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ff__destination

Tff7b72def Td2a8ffset_sourceTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3sourceTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffsource Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3sourceTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__source Tff7b72= Te6edf3source
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffInvalid source set on LXMessageTa5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffCannot reassign source on LXMessageTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffget_sourceTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ff__source

Tff7b72def Td2a8ffset_delivery_destinationTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3delivery_destinationTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__delivery_destination Tff7b72= Te6edf3delivery_destination

Tff7b72def Td2a8ffregister_delivery_callbackTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3callbackTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__delivery_callback Tff7b72= Te6edf3callback

Tff7b72def Td2a8ffregister_failed_callbackTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3callbackTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8fffailed_callback Tff7b72= Te6edf3callback

Tff7b72def Td2a8ffpackTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8fftimestamp Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8fftimestamp Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffpayload Tff7b72= Tb4b4b4[Tff7b72selfTff7b72.Td2a8fftimestampTb4b4b4, Tff7b72selfTff7b72.Td2a8fftitleTb4b4b4, Tff7b72selfTff7b72.Td2a8ffcontentTb4b4b4, Tff7b72selfTff7b72.Td2a8fffieldsTb4b4b4]

Te6edf3hashed_part Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Te6edf3hashed_part Tff7b72+Tff7b72= Tff7b72selfTff7b72.Td2a8ff__destinationTff7b72.Td2a8ffhash
Te6edf3hashed_part Tff7b72+Tff7b72= Tff7b72selfTff7b72.Td2a8ff__sourceTff7b72.Td2a8ffhash
Te6edf3hashed_part Tff7b72+Tff7b72= Te6edf3msgpackTff7b72.Td2a8ffpackbTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpayloadTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffhash Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8fffull_hashTb4b4b4(Te6edf3hashed_partTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffmessage_id Tff7b72= Tff7b72selfTff7b72.Td2a8ffhash
Te6edf3signed_part Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Te6edf3signed_part Tff7b72+Tff7b72= Te6edf3hashed_part
Te6edf3signed_part Tff7b72+Tff7b72= Tff7b72selfTff7b72.Td2a8ffhash
Tff7b72selfTff7b72.Td2a8ffsignature Tff7b72= Tff7b72selfTff7b72.Td2a8ff__sourceTff7b72.Td2a8ffsignTb4b4b4(Te6edf3signed_partTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffsignature_validated Tff7b72= Tff7b72True

Tff7b72selfTff7b72.Td2a8ffpacked Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Tff7b72selfTff7b72.Td2a8ffpacked Tff7b72+Tff7b72= Tff7b72selfTff7b72.Td2a8ff__destinationTff7b72.Td2a8ffhash
Tff7b72selfTff7b72.Td2a8ffpacked Tff7b72+Tff7b72= Tff7b72selfTff7b72.Td2a8ff__sourceTff7b72.Td2a8ffhash
Tff7b72selfTff7b72.Td2a8ffpacked Tff7b72+Tff7b72= Tff7b72selfTff7b72.Td2a8ffsignature
Te6edf3packed_payload Tff7b72= Te6edf3msgpackTff7b72.Td2a8ffpackbTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpayloadTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffpacked Tff7b72+Tff7b72= Te6edf3packed_payload
Tff7b72selfTff7b72.Td2a8ffpacked_size Tff7b72= Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4)
Te6edf3content_size Tff7b72= Tffa657lenTb4b4b4(Te6edf3packed_payloadTb4b4b4)

T8b949e# If no desired delivery method has been defined,
T8b949e# one will be chosen according to these rules:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffdesired_method Tff7b72== Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdesired_method Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffDIRECT
T8b949e# TODO: Expand rules to something more intelligent

Tff7b72if Tff7b72selfTff7b72.Td2a8ffdesired_method Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffOPPORTUNISTICTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ff__destinationTff7b72.Td2a8fftype Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4:
Te6edf3single_packet_content_limit Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffRSA_PACKET_MAX_CONTENT
Tff7b72elif Tff7b72selfTff7b72.Td2a8ff__destinationTff7b72.Td2a8fftype Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffPLAINTb4b4b4:
Te6edf3single_packet_content_limit Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffPLAIN_PACKET_MAX_CONTENT

Tff7b72if Te6edf3content_size Tff7b72> Te6edf3single_packet_content_limitTb4b4b4:
Tff7b72raise Tf85149TypeErrorTb4b4b4(Ta5d6ff"Ta5d6ffLXMessage desired opportunistic delivery method, but content exceeds single-packet size.Ta5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffOPPORTUNISTIC
Tff7b72selfTff7b72.Td2a8ffrepresentation Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffPACKET
Tff7b72selfTff7b72.Td2a8ff__delivery_destination Tff7b72= Tff7b72selfTff7b72.Td2a8ff__destination

Tff7b72elif Tff7b72selfTff7b72.Td2a8ffdesired_method Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffDIRECT Tff7b72or Tff7b72selfTff7b72.Td2a8ffdesired_method Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffPROPAGATEDTb4b4b4:
Te6edf3single_packet_content_limit Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffLINK_PACKET_MAX_CONTENT
Tff7b72if Te6edf3content_size Tff7b72<Tff7b72= Te6edf3single_packet_content_limitTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72= Tff7b72selfTff7b72.Td2a8ffdesired_method
Tff7b72selfTff7b72.Td2a8ffrepresentation Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffPACKET
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72= Tff7b72selfTff7b72.Td2a8ffdesired_method
Tff7b72selfTff7b72.Td2a8ffrepresentation Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffRESOURCE
Tff7b72elseTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffAttempt to re-pack LXMessage Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tff7b72selfTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff that was already packedTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffsendTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdetermine_transport_encryptionTb4b4b4(Tb4b4b4)

Tff7b72if Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffOPPORTUNISTICTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__as_packetTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffsendTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffdelivery_callbackTb4b4b4(Tff7b72selfTff7b72.Td2a8ff__mark_deliveredTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffstate Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffSENT
Tff7b72elif Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffDIRECTTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffstate Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffSENDING
Tff7b72selfTff7b72.Td2a8ffresource_representation Tff7b72= Tff7b72selfTff7b72.Td2a8ff__as_resourceTb4b4b4(Tb4b4b4)
Tff7b72elif Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffPROPAGATEDTb4b4b4:
T8b949e# TODO: Implement propagation
Tff7b72pass

Tff7b72def Td2a8ffdetermine_transport_encryptionTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffshould_allow_unencryptedTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_UNENCRYPTED
Tff7b72elseTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffOPPORTUNISTICTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffdestinationTff7b72.Td2a8fftype Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72True
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_RSA
Tff7b72elif Te6edf3destination_type Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffGROUPTb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72True
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_AES
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_UNENCRYPTED
Tff7b72elif Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffDIRECTTb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72True
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_EC
Tff7b72elif Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffPROPAGATEDTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffdestinationTff7b72.Td2a8fftype Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72True
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_RSA
Tff7b72elif Te6edf3destination_type Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffGROUPTb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72True
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_AES
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_UNENCRYPTED
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_UNENCRYPTED

Tff7b72def Td2a8ff__mark_deliveredTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3receipt Tff7b72= Tff7b72NoneTb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffReceived delivery notification for Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffstate Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffDELIVERED

Tff7b72if Tff7b72selfTff7b72.Td2a8ff__delivery_callback Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__delivery_callbackTb4b4b4(Tff7b72selfTb4b4b4)

Tff7b72def Td2a8ff__resource_concludedTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3resourceTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3resourceTff7b72.Td2a8ffstatus Tff7b72== Te6edf3RNSTff7b72.Td2a8ffResourceTff7b72.Td2a8ffCOMPLETETb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__mark_deliveredTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3resourceTff7b72.Td2a8fflinkTff7b72.Td2a8ffteardownTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffstate Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffOUTBOUND


Tff7b72def Td2a8ff__update_transfer_progressTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3resourceTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffprogress Tff7b72= Te6edf3resourceTff7b72.Td2a8ffprogressTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ff__as_packetTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffpackTb4b4b4(Tb4b4b4)

Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ff__delivery_destinationTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffCanTa5d6ff'Ta5d6fft synthesize packet for LXMF message before delivery destination is knownTa5d6ff"Tb4b4b4)

Tff7b72if Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffOPPORTUNISTICTb4b4b4:
Tff7b72return Te6edf3RNSTff7b72.Td2a8ffPacketTb4b4b4(Tff7b72selfTff7b72.Td2a8ff__delivery_destinationTb4b4b4, Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4[Te6edf3LXMessageTff7b72.Td2a8ffDESTINATION_LENGTHTb4b4b4:Tb4b4b4]Tb4b4b4)
Tff7b72elif Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffDIRECT Tff7b72or Tff7b72selfTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffPROPAGATEDTb4b4b4:
Tff7b72return Te6edf3RNSTff7b72.Td2a8ffPacketTb4b4b4(Tff7b72selfTff7b72.Td2a8ff__delivery_destinationTb4b4b4, Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4)

Tff7b72def Td2a8ff__as_resourceTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffpackTb4b4b4(Tb4b4b4)

Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ff__delivery_destinationTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffCanTa5d6ff'Ta5d6fft synthesize resource for LXMF message before delivery destination is knownTa5d6ff"Tb4b4b4)

Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ff__delivery_destinationTff7b72.Td2a8fftype Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffLINKTb4b4b4:
Tff7b72raise Tf85149TypeErrorTb4b4b4(Ta5d6ff"Ta5d6ffTried to synthesize resource for LXMF message on a delivery destination that was not a linkTa5d6ff"Tb4b4b4)

Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ff__delivery_destinationTff7b72.Td2a8ffstatus Tff7b72== Te6edf3RNSTff7b72.Td2a8ffLinkTff7b72.Td2a8ffACTIVETb4b4b4:
Tff7b72raise Tf85149ConnectionErrorTb4b4b4(Ta5d6ff"Ta5d6ffTried to synthesize resource for LXMF message on a link that was not activeTa5d6ff"Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffprogress Tff7b72= T79c0ff0.0
Tff7b72return Te6edf3RNSTff7b72.Td2a8ffResourceTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4, Tff7b72selfTff7b72.Td2a8ff__delivery_destinationTb4b4b4, Te6edf3callback Tff7b72= Tff7b72selfTff7b72.Td2a8ff__resource_concludedTb4b4b4, Te6edf3progress_callback Tff7b72= Tff7b72selfTff7b72.Td2a8ff__update_transfer_progressTb4b4b4)

Tff7b72def Td2a8ffwrite_to_directoryTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3directory_pathTb4b4b4)Tb4b4b4:
Te6edf3file_name Tff7b72= Te6edf3RNSTff7b72.Td2a8ffhexrepTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhashTb4b4b4, Te6edf3delimitTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3file_path Tff7b72= Te6edf3directory_pathTff7b72+Ta5d6ff"Ta5d6ff/Ta5d6ff"Tff7b72+Te6edf3file_name

Tff7b72tryTb4b4b4:
Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffpackTb4b4b4(Tb4b4b4)

Te6edf3container Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffstateTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffstateTb4b4b4,
Ta5d6ff"Ta5d6fflxmf_bytesTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffpackedTb4b4b4,
Ta5d6ff"Ta5d6fftransport_encryptedTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8fftransport_encryptedTb4b4b4,
Ta5d6ff"Ta5d6fftransport_encryptionTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8fftransport_encryption
Tb4b4b4}

Te6edf3packed_container Tff7b72= Te6edf3msgpackTff7b72.Td2a8ffpackbTb4b4b4(Te6edf3containerTb4b4b4)

Te6edf3file Tff7b72= Tffa657openTb4b4b4(Te6edf3file_pathTb4b4b4, Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4)
Te6edf3fileTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3packed_containerTb4b4b4)
Te6edf3fileTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)

Tff7b72return Te6edf3file_path

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError while writing LXMF message to file Tffea00\"Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3file_pathTb4b4b4)Tff7b72+Ta5d6ff"Tffea00\"Ta5d6ff. The contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72return Tff7b72None


Tf0883e@staticmethod
Tff7b72def Td2a8ffunpack_from_bytesTb4b4b4(Te6edf3lxmf_bytesTb4b4b4)Tb4b4b4:
Te6edf3destination_hash Tff7b72= Te6edf3lxmf_bytesTb4b4b4[Tb4b4b4:Te6edf3LXMessageTff7b72.Td2a8ffDESTINATION_LENGTHTb4b4b4]
Te6edf3source_hash Tff7b72= Te6edf3lxmf_bytesTb4b4b4[Te6edf3LXMessageTff7b72.Td2a8ffDESTINATION_LENGTHTb4b4b4:T79c0ff2Tff7b72*Te6edf3LXMessageTff7b72.Td2a8ffDESTINATION_LENGTHTb4b4b4]
Te6edf3signature Tff7b72= Te6edf3lxmf_bytesTb4b4b4[T79c0ff2Tff7b72*Te6edf3LXMessageTff7b72.Td2a8ffDESTINATION_LENGTHTb4b4b4:T79c0ff2Tff7b72*Te6edf3LXMessageTff7b72.Td2a8ffDESTINATION_LENGTHTff7b72+Te6edf3LXMessageTff7b72.Td2a8ffSIGNATURE_LENGTHTb4b4b4]
Te6edf3packed_payload Tff7b72= Te6edf3lxmf_bytesTb4b4b4[T79c0ff2Tff7b72*Te6edf3LXMessageTff7b72.Td2a8ffDESTINATION_LENGTHTff7b72+Te6edf3LXMessageTff7b72.Td2a8ffSIGNATURE_LENGTHTb4b4b4:Tb4b4b4]
Te6edf3hashed_part Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff" Tff7b72+ Te6edf3destination_hash Tff7b72+ Te6edf3source_hash Tff7b72+ Te6edf3packed_payload
Te6edf3message_hash Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8fffull_hashTb4b4b4(Te6edf3hashed_partTb4b4b4)
Te6edf3signed_part Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff" Tff7b72+ Te6edf3hashed_part Tff7b72+ Te6edf3message_hash
Te6edf3unpacked_payload Tff7b72= Te6edf3msgpackTff7b72.Td2a8ffunpackbTb4b4b4(Te6edf3packed_payloadTb4b4b4)
Te6edf3timestamp Tff7b72= Te6edf3unpacked_payloadTb4b4b4[T79c0ff0Tb4b4b4]
Te6edf3title_bytes Tff7b72= Te6edf3unpacked_payloadTb4b4b4[T79c0ff1Tb4b4b4]
Te6edf3content_bytes Tff7b72= Te6edf3unpacked_payloadTb4b4b4[T79c0ff2Tb4b4b4]
Te6edf3fields Tff7b72= Te6edf3unpacked_payloadTb4b4b4[T79c0ff3Tb4b4b4]

Te6edf3destination_identity Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8ffrecallTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72if Te6edf3destination_identity Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3destination Tff7b72= Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4(Te6edf3destination_identityTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffOUTTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4, Te6edf3APP_NAMETb4b4b4, Ta5d6ff"Ta5d6ffdeliveryTa5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3destination Tff7b72= Tff7b72None
Te6edf3source_identity Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8ffrecallTb4b4b4(Te6edf3source_hashTb4b4b4)
Tff7b72if Te6edf3source_identity Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3source Tff7b72= Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4(Te6edf3source_identityTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffOUTTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4, Te6edf3APP_NAMETb4b4b4, Ta5d6ff"Ta5d6ffdeliveryTa5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3source Tff7b72= Tff7b72None

Te6edf3message Tff7b72= Te6edf3LXMessageTb4b4b4(
Te6edf3destination Tff7b72= Te6edf3destinationTb4b4b4,
Te6edf3source Tff7b72= Te6edf3sourceTb4b4b4,
Te6edf3content Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4,
Te6edf3title Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4,
Te6edf3fields Tff7b72= Te6edf3fieldsTb4b4b4,
Te6edf3destination_hash Tff7b72= Te6edf3destination_hashTb4b4b4,
Te6edf3source_hash Tff7b72= Te6edf3source_hashTb4b4b4)

Te6edf3messageTff7b72.Td2a8ffhash Tff7b72= Te6edf3message_hash
Te6edf3messageTff7b72.Td2a8ffsignature Tff7b72= Te6edf3signature
Te6edf3messageTff7b72.Td2a8ffincoming Tff7b72= Tff7b72True
Te6edf3messageTff7b72.Td2a8fftimestamp Tff7b72= Te6edf3timestamp
Te6edf3messageTff7b72.Td2a8ffpacked Tff7b72= Te6edf3lxmf_bytes
Te6edf3messageTff7b72.Td2a8ffpacked_size Tff7b72= Tffa657lenTb4b4b4(Te6edf3lxmf_bytesTb4b4b4)
Te6edf3messageTff7b72.Td2a8ffset_title_from_bytesTb4b4b4(Te6edf3title_bytesTb4b4b4)
Te6edf3messageTff7b72.Td2a8ffset_content_from_bytesTb4b4b4(Te6edf3content_bytesTb4b4b4)

Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3sourceTb4b4b4:
Tff7b72if Te6edf3sourceTff7b72.Td2a8ffidentityTff7b72.Td2a8ffvalidateTb4b4b4(Te6edf3signatureTb4b4b4, Te6edf3signed_partTb4b4b4)Tb4b4b4:
Te6edf3messageTff7b72.Td2a8ffsignature_validated Tff7b72= Tff7b72True
Tff7b72elseTb4b4b4:
Te6edf3messageTff7b72.Td2a8ffsignature_validated Tff7b72= Tff7b72False
Te6edf3messageTff7b72.Td2a8ffunverified_reason Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffSIGNATURE_INVALID
Tff7b72elseTb4b4b4:
Te6edf3signature_validated Tff7b72= Tff7b72False
Te6edf3messageTff7b72.Td2a8ffunverified_reason Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffSOURCE_UNKNOWN
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffUnpacked LXMF message signature could not be validated, since source identity is unknownTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3messageTff7b72.Td2a8ffsignature_validated Tff7b72= Tff7b72False
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffError while validating LXMF message signature. The contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)

Tff7b72return Te6edf3message
Tf0883e@staticmethod
Tff7b72def Td2a8ffunpack_from_fileTb4b4b4(Te6edf3lxmf_file_handleTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3container Tff7b72= Te6edf3msgpackTff7b72.Td2a8ffunpackbTb4b4b4(Te6edf3lxmf_file_handleTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3lxm Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffunpack_from_bytesTb4b4b4(Te6edf3containerTb4b4b4[Ta5d6ff"Ta5d6fflxmf_bytesTa5d6ff"Tb4b4b4]Tb4b4b4)

Tff7b72if Ta5d6ff"Ta5d6ffstateTa5d6ff" Tff7b72in Te6edf3containerTb4b4b4:
Te6edf3lxmTff7b72.Td2a8ffstate Tff7b72= Te6edf3containerTb4b4b4[Ta5d6ff"Ta5d6ffstateTa5d6ff"Tb4b4b4]
Tff7b72if Ta5d6ff"Ta5d6fftransport_encryptedTa5d6ff" Tff7b72in Te6edf3containerTb4b4b4:
Te6edf3lxmTff7b72.Td2a8fftransport_encrypted Tff7b72= Te6edf3containerTb4b4b4[Ta5d6ff"Ta5d6fftransport_encryptedTa5d6ff"Tb4b4b4]
Tff7b72if Ta5d6ff"Ta5d6fftransport_encryptionTa5d6ff" Tff7b72in Te6edf3containerTb4b4b4:
Te6edf3lxmTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3containerTb4b4b4[Ta5d6ff"Ta5d6fftransport_encryptionTa5d6ff"Tb4b4b4]

Tff7b72return Te6edf3lxm
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffCould not unpack LXMessage from file. The contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Tff7b72return Tff7b72None


Tff7b72class T56d364LXMRouterTb4b4b4:
Te6edf3MAX_DELIVERY_ATTEMPTS Tff7b72= T79c0ff3
Te6edf3PROCESSING_INTERVAL Tff7b72= T79c0ff5
Te6edf3DELIVERY_RETRY_WAIT Tff7b72= T79c0ff15
Te6edf3LINK_MAX_INACTIVITY Tff7b72= T79c0ff30

Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffpending_inbound Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ffpending_outbound Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72selfTff7b72.Td2a8fffailed_outbound Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ffdirect_links Tff7b72= Tb4b4b4{Tb4b4b4}
Tff7b72selfTff7b72.Td2a8ffdelivery_destinations Tff7b72= Tb4b4b4{Tb4b4b4}

Tff7b72selfTff7b72.Td2a8ffprocessing_outbound Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8ffprocessing_inbound Tff7b72= Tff7b72False

Tff7b72selfTff7b72.Td2a8ffidentity Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8fflxmf_query_destination Tff7b72= Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4(Tff7b72NoneTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffINTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffPLAINTb4b4b4, Te6edf3APP_NAMETb4b4b4, Ta5d6ff"Ta5d6ffqueryTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffpropagation_destination Tff7b72= Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4(Tff7b72selfTff7b72.Td2a8ffidentityTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffINTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4, Te6edf3APP_NAMETb4b4b4, Ta5d6ff"Ta5d6ffpropagationTa5d6ff"Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ff__delivery_callback Tff7b72= Tff7b72None

Te6edf3job_thread Tff7b72= Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Tff7b72selfTff7b72.Td2a8ffjobloopTb4b4b4)
Te6edf3job_threadTff7b72.Td2a8ffsetDaemonTb4b4b4(Tff7b72TrueTb4b4b4)
Te6edf3job_threadTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffregister_delivery_identityTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identityTb4b4b4, Te6edf3display_name Tff7b72= Tff7b72NoneTb4b4b4)Tb4b4b4:
Te6edf3delivery_destination Tff7b72= Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4(Te6edf3identityTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffINTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4, Ta5d6ff"Ta5d6fflxmfTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffdeliveryTa5d6ff"Tb4b4b4)
Te6edf3delivery_destinationTff7b72.Td2a8ffpacket_callbackTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdelivery_packetTb4b4b4)
Te6edf3delivery_destinationTff7b72.Td2a8fflink_established_callbackTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdelivery_link_establishedTb4b4b4)
Te6edf3delivery_destinationTff7b72.Td2a8ffdisplay_name Tff7b72= Te6edf3display_name

Tff7b72if Te6edf3display_name Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3delivery_destinationTff7b72.Td2a8ffset_default_app_dataTb4b4b4(Te6edf3display_nameTff7b72.Td2a8ffencodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffdelivery_destinationsTb4b4b4[Te6edf3delivery_destinationTff7b72.Td2a8ffhashTb4b4b4] Tff7b72= Te6edf3delivery_destination
Tff7b72return Te6edf3delivery_destination

Tff7b72def Td2a8ffregister_delivery_callbackTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3callbackTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__delivery_callback Tff7b72= Te6edf3callback

Tff7b72def Td2a8ffannounceTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3destination_hashTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3destination_hash Tff7b72in Tff7b72selfTff7b72.Td2a8ffdelivery_destinationsTb4b4b4:
Te6edf3delivery_destination Tff7b72= Tff7b72selfTff7b72.Td2a8ffdelivery_destinationsTb4b4b4[Te6edf3destination_hashTb4b4b4]
Te6edf3delivery_destinationTff7b72.Td2a8ffannounceTb4b4b4(Te6edf3delivery_destinationTff7b72.Td2a8ffdisplay_nameTff7b72.Td2a8ffencodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)Tb4b4b4)

Tff7b72def Td2a8ffhandle_outboundTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3lxmessageTb4b4b4)Tb4b4b4:
Te6edf3lxmessageTff7b72.Td2a8ffstate Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffOUTBOUND
Tff7b72if Tff7b72not Te6edf3lxmessageTff7b72.Td2a8ffpackedTb4b4b4:
Te6edf3lxmessageTff7b72.Td2a8ffpackTb4b4b4(Tb4b4b4)

Te6edf3lxmessageTff7b72.Td2a8ffdetermine_transport_encryptionTb4b4b4(Tb4b4b4)

Tff7b72while Tff7b72selfTff7b72.Td2a8ffprocessing_outboundTb4b4b4:
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.1Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffpending_outboundTff7b72.Td2a8ffappendTb4b4b4(Te6edf3lxmessageTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffprocess_outboundTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8fflxmf_deliveryTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3lxmf_dataTb4b4b4, Te6edf3destination_type Tff7b72= Tff7b72NoneTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3message Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffunpack_from_bytesTb4b4b4(Te6edf3lxmf_dataTb4b4b4)

Tff7b72if Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffshould_allow_unencryptedTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3messageTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72False
Te6edf3messageTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_UNENCRYPTED
Tff7b72elseTb4b4b4:
Tff7b72if Te6edf3destination_type Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4:
Te6edf3messageTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72True
Te6edf3messageTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_RSA
Tff7b72elif Te6edf3destination_type Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffGROUPTb4b4b4:
Te6edf3messageTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72True
Te6edf3messageTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_AES
Tff7b72elif Te6edf3destination_type Tff7b72== Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffLINKTb4b4b4:
Te6edf3messageTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72True
Te6edf3messageTff7b72.Td2a8fftransport_encryption Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffENCRYPTION_DESCRIPTION_EC
Tff7b72elseTb4b4b4:
Te6edf3messageTff7b72.Td2a8fftransport_encrypted Tff7b72= Tff7b72False
Te6edf3messageTff7b72.Td2a8fftransport_encryption Tff7b72= Tff7b72None

Tff7b72if Tff7b72selfTff7b72.Td2a8ff__delivery_callback Tff7b72!= Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff__delivery_callbackTb4b4b4(Te6edf3messageTb4b4b4)

Tff7b72return Tff7b72True

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffCould not assemble LXMF message from received dataTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_NOTICETb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72return Tff7b72False


Tff7b72def Td2a8ffdelivery_packetTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3dataTb4b4b4, Te6edf3packetTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3packetTff7b72.Td2a8ffdestinationTff7b72.Td2a8fftype Tff7b72!= Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffLINKTb4b4b4:
Te6edf3lxmf_data Tff7b72= Ta5d6ffbTa5d6ff"Ta5d6ff"
Te6edf3lxmf_data Tff7b72+Tff7b72= Te6edf3packetTff7b72.Td2a8ffdestinationTff7b72.Td2a8ffhash
Te6edf3lxmf_data Tff7b72+Tff7b72= Te6edf3data
Tff7b72elseTb4b4b4:
Te6edf3lxmf_data Tff7b72= Te6edf3data

Tff7b72if Tff7b72selfTff7b72.Td2a8fflxmf_deliveryTb4b4b4(Te6edf3lxmf_dataTb4b4b4, Te6edf3packetTff7b72.Td2a8ffdestinationTff7b72.Td2a8fftypeTb4b4b4)Tb4b4b4:
Te6edf3packetTff7b72.Td2a8ffproveTb4b4b4(Tb4b4b4)

Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffException occurred while parsing incoming LXMF data.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe contained exception was: Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)

Tff7b72def Td2a8ffdelivery_link_establishedTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3linkTb4b4b4)Tb4b4b4:
Te6edf3linkTff7b72.Td2a8ffpacket_callbackTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdelivery_packetTb4b4b4)
Te6edf3linkTff7b72.Td2a8ffset_resource_strategyTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffLinkTff7b72.Td2a8ffACCEPT_ALLTb4b4b4)
Te6edf3linkTff7b72.Td2a8ffresource_started_callbackTb4b4b4(Tff7b72selfTff7b72.Td2a8ffresource_transfer_beganTb4b4b4)
Te6edf3linkTff7b72.Td2a8ffresource_concluded_callbackTb4b4b4(Tff7b72selfTff7b72.Td2a8ffresource_transfer_concludedTb4b4b4)

Tff7b72def Td2a8ffdelivery_link_closedTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3linkTb4b4b4)Tb4b4b4:
Tff7b72pass

Tff7b72def Td2a8ffresource_transfer_beganTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3resourceTb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffTransfer began for resource Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3resourceTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)

Tff7b72def Td2a8ffresource_transfer_concludedTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3resourceTb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffTransfer concluded for resource Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3resourceTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72if Te6edf3resourceTff7b72.Td2a8ffstatus Tff7b72== Te6edf3RNSTff7b72.Td2a8ffResourceTff7b72.Td2a8ffCOMPLETETb4b4b4:
Tff7b72selfTff7b72.Td2a8fflxmf_deliveryTb4b4b4(Te6edf3resourceTff7b72.Td2a8ffdataTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3resourceTff7b72.Td2a8fflinkTff7b72.Td2a8fftypeTb4b4b4)

Tff7b72def Td2a8ffjobloopTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72while Tb4b4b4(Tff7b72TrueTb4b4b4)Tb4b4b4:
T8b949e# TODO: Improve this to scheduling, so manual
T8b949e# triggers can delay next run
Tff7b72selfTff7b72.Td2a8ffjobsTb4b4b4(Tb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(Te6edf3LXMRouterTff7b72.Td2a8ffPROCESSING_INTERVALTb4b4b4)

Tff7b72def Td2a8ffjobsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffprocess_outboundTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffclean_linksTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffclean_linksTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3closed_links Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3link_hash Tff7b72in Tff7b72selfTff7b72.Td2a8ffdirect_linksTb4b4b4:
Te6edf3link Tff7b72= Tff7b72selfTff7b72.Td2a8ffdirect_linksTb4b4b4[Te6edf3link_hashTb4b4b4]
Te6edf3inactive_time Tff7b72= Te6edf3linkTff7b72.Td2a8ffinactive_forTb4b4b4(Tb4b4b4)

Tff7b72if Te6edf3inactive_time Tff7b72> Te6edf3LXMRouterTff7b72.Td2a8ffLINK_MAX_INACTIVITYTb4b4b4:
Te6edf3linkTff7b72.Td2a8ffteardownTb4b4b4(Tb4b4b4)
Te6edf3closed_linksTff7b72.Td2a8ffappendTb4b4b4(Te6edf3link_hashTb4b4b4)

Tff7b72for Te6edf3link_hash Tff7b72in Te6edf3closed_linksTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdirect_linksTff7b72.Td2a8ffpopTb4b4b4(Te6edf3link_hashTb4b4b4)

Tff7b72def Td2a8fffail_messageTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3lxmessageTb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff failed to sendTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffpending_outboundTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3lxmessageTb4b4b4)
Tff7b72selfTff7b72.Td2a8fffailed_outboundTff7b72.Td2a8ffappendTb4b4b4(Te6edf3lxmessageTb4b4b4)

Te6edf3lxmessageTff7b72.Td2a8ffstate Tff7b72= Te6edf3LXMessageTff7b72.Td2a8ffFAILED
Tff7b72if Te6edf3lxmessageTff7b72.Td2a8fffailed_callback Tff7b72!= Tff7b72NoneTb4b4b4:
Te6edf3lxmessageTff7b72.Td2a8fffailed_callbackTb4b4b4(Te6edf3lxmessageTb4b4b4)

Tff7b72def Td2a8ffprocess_outboundTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3sender Tff7b72= Tff7b72NoneTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffprocessing_outboundTb4b4b4:
Tff7b72return

Tff7b72for Te6edf3lxmessage Tff7b72in Tff7b72selfTff7b72.Td2a8ffpending_outboundTb4b4b4:
Tff7b72if Te6edf3lxmessageTff7b72.Td2a8ffstate Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffDELIVEREDTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffDelivery has occurred for Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff, removing from outbound queueTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffpending_outboundTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3lxmessageTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffStarting outbound processing for Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
T8b949e# Outbound handling for opportunistic messages
Tff7b72if Te6edf3lxmessageTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffOPPORTUNISTICTb4b4b4:
Tff7b72if Te6edf3lxmessageTff7b72.Td2a8ffdelivery_attempts Tff7b72<Tff7b72= Te6edf3LXMRouterTff7b72.Td2a8ffMAX_DELIVERY_ATTEMPTSTb4b4b4:
Tff7b72if Tff7b72not Tffa657hasattrTb4b4b4(Te6edf3lxmessageTb4b4b4, Ta5d6ff"Ta5d6ffnext_delivery_attemptTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72> Te6edf3lxmessageTff7b72.Td2a8ffnext_delivery_attemptTb4b4b4:
Te6edf3lxmessageTff7b72.Td2a8ffdelivery_attempts Tff7b72+Tff7b72= T79c0ff1
Te6edf3lxmessageTff7b72.Td2a8ffnext_delivery_attempt Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3LXMRouterTff7b72.Td2a8ffDELIVERY_RETRY_WAIT
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffOpportunistic delivery attempt Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffdelivery_attemptsTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff for Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Te6edf3lxmessageTff7b72.Td2a8ffsendTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffMax delivery attempts reached for oppertunistic Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72selfTff7b72.Td2a8fffail_messageTb4b4b4(Te6edf3lxmessageTb4b4b4)

T8b949e# Outbound handling for messages transferred
T8b949e# over a direct link to the final recipient
Tff7b72elif Te6edf3lxmessageTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffDIRECTTb4b4b4:
Tff7b72if Te6edf3lxmessageTff7b72.Td2a8ffdelivery_attempts Tff7b72<Tff7b72= Te6edf3LXMRouterTff7b72.Td2a8ffMAX_DELIVERY_ATTEMPTSTb4b4b4:
Te6edf3delivery_destination_hash Tff7b72= Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhash

Tff7b72if Te6edf3delivery_destination_hash Tff7b72in Tff7b72selfTff7b72.Td2a8ffdirect_linksTb4b4b4:
T8b949e# A link already exists, so we'll try to use it
T8b949e# to deliver the message
Te6edf3direct_link Tff7b72= Tff7b72selfTff7b72.Td2a8ffdirect_linksTb4b4b4[Te6edf3delivery_destination_hashTb4b4b4]
Tff7b72if Te6edf3direct_linkTff7b72.Td2a8ffstatus Tff7b72== Te6edf3RNSTff7b72.Td2a8ffLinkTff7b72.Td2a8ffACTIVETb4b4b4:
Tff7b72if Te6edf3lxmessageTff7b72.Td2a8ffstate Tff7b72!= Te6edf3LXMessageTff7b72.Td2a8ffSENDINGTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffStarting transfer of Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Te6edf3lxmessageTff7b72.Td2a8ffset_delivery_destinationTb4b4b4(Te6edf3direct_linkTb4b4b4)
Te6edf3lxmessageTff7b72.Td2a8ffsendTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe transfer of Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff is in progress (Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Tffa657roundTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffprogressTff7b72*T79c0ff100Tb4b4b4, T79c0ff1Tb4b4b4)Tb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff%Ta5d6ff)Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72elif Te6edf3direct_linkTff7b72.Td2a8ffstatus Tff7b72== Te6edf3RNSTff7b72.Td2a8ffLinkTff7b72.Td2a8ffCLOSEDTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe link to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff was closedTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Te6edf3lxmessageTff7b72.Td2a8ffset_delivery_destinationTb4b4b4(Tff7b72NoneTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffdirect_linksTff7b72.Td2a8ffpopTb4b4b4(Te6edf3delivery_destination_hashTb4b4b4)
Te6edf3lxmessageTff7b72.Td2a8ffnext_delivery_attempt Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3LXMRouterTff7b72.Td2a8ffDELIVERY_RETRY_WAIT
Tff7b72elseTb4b4b4:
T8b949e# Simply wait for the link to become
T8b949e# active or close
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffThe link to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff is pending, waiting for link to become activeTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72elseTb4b4b4:
T8b949e# No link exists, so we'll try to establish one, but
T8b949e# only if we've never tried before, or the retry wait
T8b949e# period has elapsed.
Tff7b72if Tff7b72not Tffa657hasattrTb4b4b4(Te6edf3lxmessageTb4b4b4, Ta5d6ff"Ta5d6ffnext_delivery_attemptTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72> Te6edf3lxmessageTff7b72.Td2a8ffnext_delivery_attemptTb4b4b4:
Te6edf3lxmessageTff7b72.Td2a8ffdelivery_attempts Tff7b72+Tff7b72= T79c0ff1
Te6edf3lxmessageTff7b72.Td2a8ffnext_delivery_attempt Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3LXMRouterTff7b72.Td2a8ffDELIVERY_RETRY_WAIT
Tff7b72if Te6edf3lxmessageTff7b72.Td2a8ffdelivery_attempts Tff7b72< Te6edf3LXMRouterTff7b72.Td2a8ffMAX_DELIVERY_ATTEMPTSTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffEstablishing link to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff for delivery attempt Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffdelivery_attemptsTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Te6edf3delivery_link Tff7b72= Te6edf3RNSTff7b72.Td2a8ffLinkTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3delivery_linkTff7b72.Td2a8fflink_established_callbackTb4b4b4(Tff7b72selfTff7b72.Td2a8ffprocess_outboundTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffdirect_linksTb4b4b4[Te6edf3delivery_destination_hashTb4b4b4] Tff7b72= Te6edf3delivery_link
Tff7b72elseTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffMax delivery attempts reached for direct Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72selfTff7b72.Td2a8fffail_messageTb4b4b4(Te6edf3lxmessageTb4b4b4)

T8b949e# Outbound handling for messages transported via
T8b949e# propagation to a LXMF router network.
Tff7b72elif Te6edf3lxmessageTff7b72.Td2a8ffmethod Tff7b72== Te6edf3LXMessageTff7b72.Td2a8ffPROPAGATEDTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6ff"Ta5d6ffAttempting propagated delivery for Ta5d6ff"Tff7b72+Tffa657strTb4b4b4(Te6edf3lxmessageTb4b4b4)Tff7b72+Ta5d6ff"Ta5d6ff to Ta5d6ff"Tff7b72+Te6edf3RNSTff7b72.Td2a8ffprettyhexrepTb4b4b4(Te6edf3lxmessageTff7b72.Td2a8ffget_destinationTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffhashTb4b4b4)Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72raise Tf85149NotImplementedErrorTb4b4b4(Ta5d6ff"Ta5d6ffLXMF propagation is not implemented yetTa5d6ff"Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────